﻿// ## 2023/10/29# 铃 # 优化部分注释,优化常量显示为汉字,增加注释便意理解. ##
// ## 2023/10/28# 铃 # 完全汉化所有的注释.变量.常量.整理代码,优化逻辑. ##
// ## 2022/02/14 # 江东新风 # 部分常量中文化 ##
// ## 2021/10/04 # 江东新风 # 部分汉化 ##
// ## 2021/09/15 # 江东新风 # 更改pk::core[]函数为英文##
// ## 2020/11/17 # 江东新风 # 修正trace乱码 ##
// ## 2020/09/21 # 江东新风 # ch::add_tp替换 ##
// ## 2020/07/26 ##
/*

@制作:masterpiecek
@内容:AI部队在附近存在满足一定条件的目标部队时，针对该部队实施计略:扰乱和伪报。

[AI部队计略实施]

1.  计略执行部队执行计略所需要满足的条件(括号内的内容是设定的基本值)
1)部队存在于执行部队基准距离(8格)以内。
2)执行部队的部队气力在标准值(30)以上
3)执行部队的特定部队能力低于标准值(70)
4)执行部队的附带适性不足标准值(适性A)
5)执行部队未按兵器拥有特定特技(参考玩家设定)

2.  执行计略的部队将搜索要执行计略的对象部队
1)确认计略对象部队的条件(括号内的内容为设定的标准值)
(1)对象部队的部队兵力在标准值(1500)以上
(2)对象部队的部队气力在标准值(20)以上
(3)对象部队的特定部队能力在标准值(40)以上
(4)对象部队的部队适性超过标准值(适性C)
(5)满足执行部队对目标部队的计略成功概率条件(参考玩家设定)
-不同模式的条件不同:模式1(尝试成功的对象)，模式2(尝试概率有保障的对象)
2)对象部队之间的比较
从上位条件开始比较，如果相同，则比较下位条件
(1)对象部队的攻城战防御条件:优先考虑攻城战防御条件满足的部队;
—满足城市的耐久和兵力条件时，将优先考虑靠近城市的攻城部队;
(2)对象部队的相邻部队:如果执行部队拥有[连环]特技时，在目标部队的邻近坐标存在敌军部队的优先;
(3)对象部队的部队能力(攻击力):越高越优先
(4)对象部队的部队能力(智力):越高越优先
(5)对象部队的部队兵力:越多越优先。
(6)执行部队与对象部队的距离:越近，越优先
(7)对象部队的部队适性:越高越优先
(8)对象部队的部队气力:越高越优先。
(9)执行部队对被执行部队的计略成功率:越高越优先(仅限于成功率保障模式)
(10)对象部队的部队将领数:越多越优先。
(11)对象部队周围存在的执行部队的敌军部队数量(五格以内):越少越优先
(12)对象部队周围存在的执行部队中敌军士兵数量(五格以内):越少越优先
(12)对象部队周围执行部队的我军部队数量(五格以内):越多越优先
(14)对象部队周围执行部队我军士兵数量(五格以内):越多越优先
3. 如果执行部队满足计略的执行条件并且目标部队存在，则检查执行部队是否需要移动
1)对象部队存在于执行部队的计略范围以外的;
2)执行部队位于着火地形之上的;
3)执行部队位于特定设施范围内的;
—自动攻击设施及陷阱范围
4)执行部队是出征部队时。
4. 如果计略部队需要移动，则搜索移动候选坐标
1)确认移动候选坐标的条件
(1)不受地形损害(未研究难所行军时)的坐标
(2)不是着火地形的坐标
(3)特定设施范围以外的坐标
—自动攻击设施及陷阱范围
2)候选坐标之间的比较
—远离目标部队的坐标优先
5. 当所有这些条件都满足时，执行部队就会对目标部队执行计略
——如果有条件，则执行AI现有任务
1)需要移动时，如有可移动坐标存在，则移动后执行计略
2)不需要移动时，则在原位置执行计略
*/

namespace AI_Unit_StrategyPerform
{

	/// ============================================ < Player Setting > ============================================

	/// [ 一般设定 ]

	/// AI计略执行是否适用对应部队
	const array<bool> AI_Unit_StrategyPerform_野战部队_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<bool> AI_Unit_StrategyPerform_出征部队_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };

	/// 异族势力部队是否适用
	const bool 异族势力_适用 = true;

	/// 电脑势力部队的情况下，是否只针对玩家势力的部队实施计略。
	const bool 电脑部队_计略实施对象_仅限玩家 = false;

	// 试图按照输入项目的顺序计略(计略项目的顺序只能修改和删除，禁止添加新项目)
	const array<int> 执行计略_一览 = { 计略_扰乱, 计略_伪报 };

	/// 执行部队为执行计谋而搜索对对象部队的标准距离(只搜索标准距离以内的目标部队)
	const int 执行计略_标准距离 = 8;

	/// 执行部队对目标部队的计谋成功概率相关设定模式   실행부대의 대상부대에 대한 계략 성공확률 관련 설정 모드
	// 模式1:成功保障对象(只针对成功概率高、成功可靠的部队计谋，不尝试失败的部队)
	// 模式2:概率保障对象(只针对成功概率高于设定的标准概率的部队实施计谋，因此可能会失败)
	const array<int> 成功概率_适用模式 = {/*玩家委任军团*/ 2, /*电脑*/ 2 };

	// 模式2相关设定:如果目标部队的计谋成功概率低于设定值，就不尝试(只适用于模式2)
	const array<int> 执行标准_成功概率 = {/*玩家委任军团*/ 75, /*电脑*/ 75 };

	/// 目标部队附近的执行部队搜索移动的候选坐标时设定

	// 如果候选坐标是毒泉、悬崖地形，是否将其排除在候选坐标之外。
	const array<bool> 候选坐标_搜索_毒泉栈道_除外 = {/*玩家委任军团*/ true, /*电脑*/ true };

	// 如果候选坐标着火，是否将其排除在候选坐标之外。
	const array<bool> 候选坐标_搜索_着火地形_除外 = {/*玩家委任军团*/ true, /*电脑*/ true };

	// 如果候选坐标在特定设施范围内，是否将其排除在候选坐标之外。
	const array<bool> 候选坐标_搜索_特定设施范围_除外 = {/*玩家委任军团*/ true, /*电脑*/ true };

	/// 设定执行部队要回避的设施
	// 1.确认是否需要在当前位置移动执行部队时
	// 2.确认候选移动坐标的设施范围时

	const array<array<int>> 回避对象_设施 =
	{
		/*固定设施*/ {设施_都市, 设施_关隘, 设施_港口},
		/*军事设施*/ {设施_阵, 设施_砦, 设施_城塞, 设施_弓橹, 设施_连弩橹, 设施_投石台, 设施_石兵八阵, 设施_根据地1, 设施_根据地2},
		/* 障碍物 */ {},
		/*  陷阱  */ {设施_火种, 设施_火焰种, 设施_火球, 设施_火焰球, 设施_火船, 设施_业火球, 设施_业火种, 设施_落石},
		/*内政设施*/ {} };

/// -------------------------------------------------------------------------------------------------------

/// [ 执行部队相关条件 ]

/// 如果执行部队的部队种类是运输部队，是否实行计谋
	const array<bool> 执行部队_运输部队_适用 = {/*玩家委任军团*/ false, /*电脑*/ false };

	// 执行部队的气力不足标准值时不实行计谋(气力不足计谋消耗气力时当然不可能)
	const array<bool> 执行部队_气力条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 执行部队_气力标准 = {/*玩家委任军团*/ 30, /*电脑*/ 30 };

	/// 执行部队特定部队能力超过标准值时，不执行计谋
	const array<bool> 执行部队_能力条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const int 执行部队_适用能力 = 部队能力_攻击;
	const array<int> 执行部队_能力标准 = {/*玩家委任军团*/ 90, /*电脑*/ 90 }; ////////！！！！！！！！！！！或许需要按照新版本更改，毕竟能力和适性都上升了

	/// 执行部队的适性超过标准值时，不执行计谋
	// 参考:如果使用适性S以后的适性，应输入数(适性C的数值为0，以后适性每上升一级，数值+1)
	const array<bool> 执行部队_适性条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 执行部队_适性标准 = {/*玩家委任军团*/ 适性_S, /*电脑*/ 适性_S };

	/// 执行部队拥有按兵器设定的特定特技时，不执行计谋

	// 是否适用特技条件设定 특기조건 적용여부 설정
	const array<bool> 执行部队_特技条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };

	// 设定各特技的特技条件是否适用 특기별 특기조건 적용여부 설정
	const bool 执行部队_鬼门特技_适用 = true;  // 应用于所有武器。
	const bool 执行部队_妖术特技_适用 = false; // 应用于所有武器。
	const bool 执行部队_连战特技_适用 = false; // 应用于除剑之外的所有武器。
	const bool 执行部队_霸王特技_适用 = true;  // 应用于除剑之外的所有武器。
	const bool 执行部队_勇将特技_适用 = true;  // 应用于除剑之外的所有武器。
	const bool 执行部队_擒拿特技_适用 = true;  // 应用于除剑之外的所有武器。

	// 各兵器适用特技条件的特技设定
	const array<array<int>> 执行部队_按兵器_适用特技 =
	{
		/* 剑 */ {},
		/* 枪 */ {特技_神将, 特技_飞将, 特技_斗神, 特技_枪神, 特技_枪将, 特技_猛者},
		/* 戟 */ {特技_神将, 特技_飞将, 特技_斗神, 特技_戟神, 特技_戟将, 特技_猛者, 特技_攻心, 特技_威风},
		/* 弩 */ {特技_神将, 特技_飞将, 特技_弓神, 特技_骑将},
		/*战马*/ {特技_神将, 特技_飞将, 特技_骑神, 特技_骑将, 特技_疾驰},
		/*冲车*/ {特技_工神, 特技_攻城},
		/*井阑*/ {特技_工神, 特技_攻城, 特技_射程},
		/*投石*/ {特技_工神, 特技_攻城, 特技_射程},
		/*木兽*/ {特技_工神, 特技_攻城},
		/*走舸*/ {特技_水神, 特技_水将},
		/*楼船*/ {特技_水神, 特技_水将},
		/*斗舰*/ {特技_水神, 特技_水将} };

/// -------------------------------------------------------------------------------------------------------

/// [ 对象部队相关条件 ]

/// 如果目标部队的兵力不足标准值，将被排除在计谋实施对象之外。
	const array<bool> 对象部队_兵力条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 对象部队_兵力标准 = {/*玩家委任军团*/ 1500, /*电脑*/ 1500 };

	/// 如果目标部队的气力不足标准值，将被排除在计谋实施对象之外。
	const array<bool> 对象部队_气力条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 对象部队_气力标准 = {/*玩家委任军团*/ 20, /*电脑*/ 20 };

	/// 对象部队的特定部队能力不足标准值的，将被排除在计谋实施对象之外。
	const array<bool> 对象部队_能力条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 对象部队_能力标准 = {/*玩家委任军团*/ 40, /*电脑*/ 40 };
	const int 对象部队_适用能力 = 部队能力_攻击;

	/// 对象部队的的适性低于标准值时，将被排除在计谋实施对象之外。
	// 参考:如果使用适性S以后的适性，应输入数(适性C的数值为0，以后适性每上升一级，数值+1)

	const array<bool> 对象部队_适性条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const array<int> 对象部队_适性标准 = {/*玩家委任军团*/ 适性_B, /*电脑*/ 适性_B };

	/// 通过计谋条件的目标部队排序设定

	// 对在城市附近满足攻城战防御条件的目标部队优先实施计谋

	const array<bool> 攻城战_防御条件_适用 = {/*玩家委任军团*/ true, /*电脑*/ true };
	const int 攻城战_防御条件_标准距离 = 6;
	const int 攻城战_防御条件_标准耐久比率 = 30;
	const int 攻城战_防御条件_兵力标准 = 5000;

	/// 实行部队拥有连环特技的，优先对有邻近部队的对象部队实行计谋。
	const array<bool> 连环特技_邻近部队_优先 = {/*玩家委任军团*/ true, /*电脑*/ true };

	/// =========================================================================================

	// 调试设置
	const bool debug_func261_prev_handler_check = false;
	const bool debug_func262_prev_handler_check = false;
	const bool debug_serach_pos_to_move = false;
	const bool debug_strategy_success_info = false;
	const bool debug_dst_unit_sort_info = false;

	class Main
	{

		///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		// 用于AI脚本函数链的旧处理器存储
		pk::func261_t @prev_callback_261;

		// 用于储存部队任务处理器函数链的转移处理器
		pk::func262_t @prev_callback_262;

		// 执行部队在搜索计谋对象部队时，可在该对象部队附近储存可移动的候补坐标。
		array<pk::point> 各目标部队_候选坐标(部队_末, -1);

		// 用于调试候选移动坐标搜索函数
		pk::point range_pos_;

		// 用于排列候补对象部队
		int strategy_id_;
		pk::unit @src_unit_;

		// 직直线型陷阱设施范围确认的参考
		array<array<int>> 方向对应的直线坐标索引 =
		{
			/*西北*/ {4, 15, 32, 55, 84, 119, 160, 207}, /* 北 */ {5, 17, 35, 59, 89, 125, 167, 215},
			/*东北*/ {0, 7, 20, 39, 64, 95, 132, 175}, /*西南*/ {3, 13, 29, 51, 79, 113, 153, 199},
			/* 南 */ {2, 11, 26, 47, 74, 107, 146, 191}, /*东南*/ {1, 9, 23, 43, 69, 101, 139, 183} };

	/**
		[额外考虑]

		在地形损害及设施范围条件方面，执行部队在搜索移动候选坐标时，满足了其他条件。
		如果不满足相关条件而没有可移动的坐标，是否无视并实施计谋
	*/

	///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		Main()
		{
			// 261函数前处理器存储、函数初始化、函数重新定义
			//@prev_callback_261 = cast<pk::func261_t @>(pk::get_func(261));
			//pk::reset_func(261);
			//pk::set_func(261, pk::func261_t(func261));

			// 262函数前处理器存储、函数初始化、函数重新定义
			//@prev_callback_262 = cast<pk::func262_t @>(pk::get_func(262));
			//pk::reset_func(262);
			//pk::set_func(262, pk::func262_t(func262));
		}

		///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		/**
		@param force : AI势力
		@return如果是自己处理的，true。 如果想交给电脑，就false。！！！！！不确定这个是否会造成二动
		*/
		/// 注意:如果使用AI脚本函数(261)，玩家1军团已经被排除在外。
		/// 参考:261函数是整个AI脚本，所以部队在执行计略后，必须无条件地改变以前的处理器。

		bool func261(pk::force @force)
		{
			if (debug_func261_prev_handler_check)
			{
				string force_name = pk::decode(pk::get_name(force));
				pk::info(force_name + " 势力 - 261函数之前是否被调用 : " + (prev_callback_261 is null ? "否" : "是"));
			}

			for (int unit_id = 0; unit_id < 部队_末; unit_id++)
			{
				pk::unit @unit = pk::get_unit(unit_id);
				if (!pk::is_alive(unit))
					continue;
				if (unit.get_force_id() != force.get_id())
					continue;

				// 除外出征部队 (部队坐标与部队所属据点坐标相同的除外)
				pk::building @building = pk::get_building(pk::get_service(unit));
				if (pk::is_alive(building) and unit.pos == building.pos)
					continue;

				strategy_action_of_AI_unit(unit, force, /*is_deployed*/ false);
			}

			if (prev_callback_261 is null)
				return false;
			return prev_callback_261(force);
		}

		/**
			@param unit : 部队执行任务部队
			@return如果是自己处理的，true。 如果想交给电脑，就false。
		*/
		/// 注意:pk::run_order函数执行时，脚本将执行。 (在262函数内使用pk: run_order函数时发生无限循环)
		/// 参考:262函数是一个仅限于部队任务处理器的脚本，因此，如果该部队执行了计略，行动就会完成，所以不链条上的处理器。

		bool func262(pk::unit_manager @unit_mgr, pk::unit@ unit)
		{
			if (debug_func262_prev_handler_check)
			{
				string unit_name = pk::decode(pk::get_name(unit));
				pk::info(unit_name + " - 262函数之前是否被调用 : " + (prev_callback_262 is null ? "否" : "是"));
			}

			// 只有在执行部队出征部队时才实行(部队坐标与部队所属据点坐标相同时实行)
			pk::building @building = pk::get_building(pk::get_service(unit));
			if (pk::is_alive(building) and unit.pos == building.pos)
			{
				pk::force @force = pk::get_force(unit.get_force_id());
				strategy_action_of_AI_unit(unit, force, /*is_deployed*/ true);

				// 如果执行了计略，则不连锁前置处理器
				if (unit.pos != building.pos)
					return true;
			}

			if (prev_callback_262 is null)
				return false;
			return prev_callback_262(unit_mgr,unit);
		}

		///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		void strategy_action_of_AI_unit(pk::unit @unit, pk::force @force, bool is_deployed)
		{
			if (pk::is_player_controlled(unit))
				return;

			if (!is_normal_game())
				return;
			if (force is null) return;
			if (!pk::is_normal_force(force) and !异族势力_适用)
				return;

			// 设定条件:执行部队的操作主体确认是否适用(玩家委任军团，电脑)
			int controller_index = get_controller_index(unit);
			if (is_deployed)
			{
				// 如果被执行的部队是出征部队，确认是否适用
				if (!AI_Unit_StrategyPerform_出征部队_适用[controller_index])
					return;
			}
			else
			{
				// 如果被执行的部队是野战部队，确认是否适用
				if (!AI_Unit_StrategyPerform_野战部队_适用[controller_index])
					return;
			}

			for (int arr_index = 0; arr_index < int(执行计略_一览.length); arr_index++)
			{
				int strategy_id = 执行计略_一览[arr_index];
				func_strategy_perform(unit, force, strategy_id, controller_index, is_deployed);
			}
		}

		// 执行部队存在计略对象部队时实行计略(为执行计略需要执行部队移动时，移动后实行)
		void func_strategy_perform(pk::unit @src_unit, pk::force @src_force, int strategy_id, int controller_index, bool is_deployed)
		{
			@src_unit_ = @src_unit;
			strategy_id_ = strategy_id;

			int energy_cost = get_energy_cost(src_unit, strategy_id);
			if (!func_执行部队_满足条件(src_unit, strategy_id, energy_cost, controller_index))
				return;

			int strategy_range = src_unit.has_skill(特技_鬼谋) ? 3 : 2;
			pk::unit @dst_unit = get_dst_unit(src_unit, src_force, strategy_id, strategy_range, controller_index, is_deployed);
			if (!pk::is_alive(dst_unit))
				return;

			// 대상부대 검색 시 저장했던 실행부대의 이동후보좌표 반환 : 이동이 필요한 경우에만 저장된 상태
			pk::point pos_to_move = 各目标部队_候选坐标[dst_unit.get_id()];
			if (pk::is_valid_pos(pos_to_move))
			{
				// 如果移动候选坐标有效(保存)，执行部队向候选坐标移动:执行部队移动命令
				/// 参考:pk::get_path(unit, unit。 pos, pos)函数使用时发生强制终止现象
				if (is_deployed)
				{
					/// 参考: 不能在262函数里执行run_order，否则会产生死循环
					// array<pk::point> unit_path = pk::get_path(src_unit, src_unit.pos, pos_to_move);
					array<pk::point> unit_path = { src_unit.pos, pos_to_move }; // 临时措施：但移动动画不自然
					pk::move(src_unit, unit_path);
				}
				else
				{
					pk::set_order(src_unit, 部队任务_移动, pos_to_move);
					pk::run_order(src_unit);
				}
			}


			// 执行部队计略施行(延环特技，反计特技反映)
			func_执行计略(src_unit, src_force, dst_unit, strategy_id, energy_cost, controller_index, is_deployed);
		}

		// 检查策略执行部队是否满足执行条件
		bool func_执行部队_满足条件(pk::unit @src_unit, int strategy_id, int energy_cost, int controller_index)
		{
			// 基本条件：检查执行部队周围是否存在敌方部队，距离不超过执行策略的标准距离
			if (func_部队附近_敌部队数(src_unit, 执行计略_标准距离) == 0)
				return false;

			// 基本条件：如果执行部队的部队任务是撤退，则不满足条件
			if (src_unit.order == 部队任务_撤退)
				return false;

			// 异常状态的部队不应该移动并执行
			if (src_unit.status == 部队状态_混乱 or src_unit.status == 部队状态_伪报 or src_unit.status == 部队状态_挑衅 or src_unit.status == 部队状态_止行)
				return false;

			// 基本条件：如果执行部队的行动已完成，则不满足条件
			if (src_unit.action_done)
				return false;

			// 基本条件：如果执行部队的部队气力低于策略消耗气力，则不满足条件
			if (int(src_unit.energy) < energy_cost)
				return false;

			// 设置条件：如果执行部队的部队类型是运输部队，并且不适用于该控制器，则不满足条件
			if (!执行部队_运输部队_适用[controller_index] && src_unit.type == 部队类型_运输)
				return false;

			// 设置条件：如果执行部队的部队气力低于基准气力，并且适用于气力条件，则不满足条件
			if (执行部队_气力条件_适用[controller_index])
			{
				if (int(src_unit.energy) < 执行部队_气力标准[controller_index])
					return false;
			}

			// 设置条件：如果执行部队的特定能力大于等于基准能力，并且适用于能力条件，则不满足条件
			if (执行部队_能力条件_适用[controller_index])
			{
				if (int(src_unit.attr.stat[执行部队_适用能力]) >= 执行部队_能力标准[controller_index])
					return false;
			}

			// 设置条件：如果执行部队的部队适性大于等于基准适性，并且适用于适性条件，则不满足条件
			int weapon_id = src_unit.weapon;
			if (执行部队_适性条件_适用[controller_index])
			{
				int src_tekisei = (weapon_id == 兵器_剑) ? 0 : pk::get_tekisei(src_unit, weapon_id);
				if (src_tekisei >= 执行部队_适性标准[controller_index])
					return false;
			}

			// 设置条件：如果执行部队根据武器类型配置的特定技能满足条件，则不满足条件
			if (执行部队_特技条件_适用[controller_index])
			{
				if (src_unit.has_skill(特技_鬼门) && 执行部队_鬼门特技_适用)
					return false;
				if (src_unit.has_skill(特技_妖术) && 执行部队_妖术特技_适用)
					return false;

				if (weapon_id != 兵器_剑)
				{
					if (src_unit.has_skill(特技_霸王) && 执行部队_霸王特技_适用)
						return false;
					if (src_unit.has_skill(特技_勇将) && 执行部队_勇将特技_适用)
						return false;
					if (src_unit.has_skill(特技_擒拿) && 执行部队_擒拿特技_适用)
						return false;

					/// 注意：如果将'18 other.xml'中的tactics_rensen'值设置为'true'，则连战技能也适用于战法
					if (src_unit.has_skill(特技_连战) and 执行部队_连战特技_适用)
						return false;
				}

				for (int arr_index = 0; arr_index < int(执行部队_按兵器_适用特技[weapon_id].length); arr_index++)
				{
					int skill_id = 执行部队_按兵器_适用特技[weapon_id][arr_index];
					if (src_unit.has_skill(skill_id))
						return false;
				}
			}

			return true;
		}

		// 根据条件满足的目标部队进行排序，然后返回优先级最高的目标部队
		pk::unit @get_dst_unit(pk::unit @src_unit, pk::force @src_force, int strategy_id, int strategy_range, int controller_index, bool is_deployed)
		{
			array<pk::unit @> dst_unit_arr = get_dst_unit_arr(src_unit, src_force, strategy_id, strategy_range, controller_index, is_deployed);
			if (int(dst_unit_arr.length) == 0)
				return null;

			if (debug_dst_unit_sort_info)
			{
				pk::message_box(pk::encode("敌方部队排序优先级的选择前"));
				for (int i = 0; i < int(dst_unit_arr.length); i++)
				{
					pk::unit @unit = dst_unit_arr[i];
					string unit_name = pk::decode(pk::get_name(unit));
					pk::message_box(pk::encode("索引目标部队" + i + ":" + unit_name + "\n部队攻击力:" + int(unit.attr.stat[部队能力_攻击]) + "\n部队属性:" + int(pk::get_tekisei(unit))));
				}
			}
			/**
				2)对象部队之间的比较
				从上位条件开始比较，如果相同，则比较下位条件
				(1)对象部队的攻城战防御条件:优先考虑攻城战防御条件满足的部队;
				—满足城市的耐久和兵力条件时，将优先考虑靠近城市的攻城部队;
				(2)对象部队的相邻部队:如果执行部队拥有[连环]特技时，在目标部队的邻近坐标存在敌军部队的优先;
				(3)对象部队的部队能力(攻击力):越高越优先
				(4)对象部队的部队能力(智力):越高越优先
				(5)对象部队的部队兵力:越多越优先。
				(6)执行部队与对象部队的距离:越近，越优先
				(7)对象部队的部队适性:越高越优先
				(8)对象部队的部队气力:越高越优先。
				(9)执行部队对被执行部队的计略成功率:越高越优先(仅限于成功率保障模式)
				(10)对象部队的部队将领数:越多越优先。
				(11)对象部队周围存在的执行部队的敌军部队数量(五格以内):越少越优先
				(12)对象部队周围存在的执行部队中敌军士兵数量(五格以内):越少越优先
				(12)对象部队周围执行部队的我军部队数量(五格以内):越多越优先
				(14)对象部队周围执行部队我军士兵数量(五格以内):越多越优先
			*/
			/**
				[参考]

				1.  如果你想反映模糊的情况，比如部队之间的条件比较时差异很小，你可以在范围内设定排序条件。
				但是，如果条件超过两个，想要排序的排列项目超过三个，就会发生项目之间无法比较的情况。
				2.  在排列或列表时，请注意设置条件出现例外的情况。
				例如，如果你不处理所有你想要在特定条件下排序的情况，那么你不能处理的情况就会在以下条件下处理。
				可以按不同的方向排列。
			*/
			// 根据条件对目标部队的项目数组进行排序
			dst_unit_arr.sort(function(a, b) {
				// 目标部队的攻城战防御条件：优先选择满足攻城战防御条件的目标部队（但应用攻城战防御条件时）
				int controller_index = main.get_controller_index(main.src_unit_);
				if (攻城战_防御条件_适用[controller_index])
				{
					bool a_is_siege_warfare = main.func_攻城战_防御条件_满足与否(main.src_unit_, a);
					bool b_is_siege_warfare = main.func_攻城战_防御条件_满足与否(main.src_unit_, b);
					if (a_is_siege_warfare and !b_is_siege_warfare)
						return true;
					else if (!a_is_siege_warfare and b_is_siege_warfare)
						return false;
				}
				// 目标部队的邻近部队：如果执行部队持有连环特技，则优先选择目标部队邻近坐标中存在执行部队的敌对部队（但仅适用于设置时）
				if (连环特技_邻近部队_优先[controller_index] and main.src_unit_.has_skill(特技_连环))
				{
					pk::unit @a_neighbor_unit = main.get_dst_neighbor_unit(main.src_unit_, a);
					pk::unit @b_neighbor_unit = main.get_dst_neighbor_unit(main.src_unit_, b);
					if (pk::is_alive(a_neighbor_unit) and !pk::is_alive(b_neighbor_unit))
						return true;
					else if (!pk::is_alive(a_neighbor_unit) and pk::is_alive(b_neighbor_unit))
						return false;
				}

				// 目标部队的部队能力（攻击力）：越大越优先
				int a_atk_stat = a.attr.stat[部队能力_攻击];
				int b_atk_stat = b.attr.stat[部队能力_攻击];
				if (a_atk_stat != b_atk_stat)
					return a_atk_stat > b_atk_stat;

				// 目标部队的部队能力（智力）：越大越优先
				int a_int_stat = a.attr.stat[部队能力_智力];
				int b_int_stat = b.attr.stat[部队能力_智力];
				if (a_int_stat != b_int_stat)
					return a_int_stat > b_int_stat;

				// 目标部队的部队兵力：越多越优先
				if (a.troops != b.troops)
					return a.troops > b.troops;

				// 执行部队与目标部队的距离：越近越优先
				int a_distance = pk::get_distance(main.src_unit_.pos, a.pos);
				int b_distance = pk::get_distance(main.src_unit_.pos, b.pos);
				if (a_distance != b_distance)
					return a_distance < b_distance;

				// 目标部队的部队适性：越高越优先
				int a_tekisei = (a.weapon != 兵器_剑) ? pk::get_tekisei(a, a.weapon) : 0;
				int b_tekisei = (b.weapon != 兵器_剑) ? pk::get_tekisei(b, b.weapon) : 0;
				if (a_tekisei != b_tekisei)
					return a_tekisei > b_tekisei;

				// 目标部队的部队气力：越大越优先
				if (a.energy != b.energy)
					return a.energy > b.energy;

				// 执行部队对目标部队的计策成功概率：越高越优先（仅适用于保证概率对象模式）
				if (成功概率_适用模式[controller_index] == /*保证概率对象*/ 2)
				{
					int a_chance = main.get_success_chance(main.src_unit_, a.pos, main.strategy_id_);
					int b_chance = main.get_success_chance(main.src_unit_, b.pos, main.strategy_id_);
					if (a_chance != b_chance)
						return a_chance > b_chance;
				}

				// 目标部队的部队构成员：越多越优先
				int a_member_count = pk::get_member_count(a);
				int b_member_count = pk::get_member_count(b);
				if (a_member_count != b_member_count)
					a_member_count > b_member_count;

				array<int> a_around_info = main.func_对象部队_附近部队_相关信息_数组(main.src_unit_, a, /*distance*/ 5);
				array<int> b_around_info = main.func_对象部队_附近部队_相关信息_数组(main.src_unit_, b, /*distance*/ 5);

				// 目标部队附近存在的敌对部队数量（5格范围内）：越少越优先
				if (a_around_info[0] != b_around_info[0])
					return a_around_info[0] < b_around_info[0];

				// 目标部队附//存在的敌对部队的士兵数量（5格范围内）：越少越优先
				if (a_around_info[1] != b_around_info[1])
					return a_around_info[1] < b_around_info[1];

				// 目标部队附近存在的友军部队数量（5格范围内）：越多越优先
				if (a_around_info[2] != b_around_info[2])
					return a_around_info[2] > b_around_info[2];

				// 目标部队附近存在的友军士兵数量（5格范围内）：越多越优先
				if (a_around_info[3] != b_around_info[3])
					return a_around_info[3] > b_around_info[3];

				return true;
			});

			if (debug_dst_unit_sort_info)
			{
				pk::message_box(pk::encode("敌方部队排序优先级的选择后"));
				for (int i = 0; i < int(dst_unit_arr.length); i++)
				{
					pk::unit @unit = dst_unit_arr[i];
					string unit_name = pk::decode(pk::get_name(unit));
					pk::message_box(pk::encode("索引目标部队" + i + ":" + unit_name));
				}
			}

			return dst_unit_arr[0];
		}
		// 如果满足目标部队的条件，并且执行部队需要移动的情况下，返回存在候选移动坐标的目标部队候选对象数组
		array<pk::unit @> get_dst_unit_arr(pk::unit @src_unit, pk::force @src_force, int strategy_id, int strategy_range, int controller_index, bool is_deployed)
		{
			// 将每个目标部队的候选坐标初始化为-1
			for (int i = 0; i < 部队_末; i++)
				各目标部队_候选坐标[i] = -1;

			// 创建用于保存目标部队候选对象的数组
			array<pk::unit @> dst_unit_arr(0);

			// 检查执行部队的计策范围内的所有坐标
			array<pk::point> range_arr = pk::range(src_unit.pos, 1, 执行计略_标准距离);
			for (int i = 0; i < int(range_arr.length); i++)
			{
				pk::point dst_pos = range_arr[i];
				pk::unit @dst_unit = pk::get_unit(dst_pos);

				// 如果目标部队已死亡，则继续下一个目标部队的检查
				if (!pk::is_alive(dst_unit))
					continue;

				// 对于计算机势力部队，仅将玩家势力部队作为计策执行的目标，根据需要进行确认
				if (电脑部队_计略实施对象_仅限玩家 and !src_unit.is_player())
				{
					if (!dst_unit.is_player())
						continue;
				}

				// 检查目标部队是否满足计策执行的条件
				if (!func_对象部队_满足条件(src_unit, dst_unit, strategy_id, controller_index))
					continue;

				/**
				 * [参考] 如果执行部队需要移动
				 *
				 * 1. 如果目标部队在执行部队的计策范围之外
				 * 2. 如果执行部队在不可通行的地形上
				 * 3. 如果执行部队在特定设施的范围内
				 * 4. 如果执行部队是出发部队
				 */

				// 如果执行部队在当前坐标需要移动，检查目标部队附近是否存在可移动的候选坐标
				int curr_distance = pk::get_distance(src_unit.pos, dst_pos);
				if (curr_distance > strategy_range or pk::is_on_fire(src_unit.pos) or is_in_facility_range(src_unit, src_unit.pos) or is_deployed)
				{
					// 搜索执行部队附近可移动的候选坐标
					pk::point pos_to_move = get_pos_to_move(src_unit, src_force, dst_unit, strategy_range, controller_index);

					// 如果不存在可移动的候选坐标，则继续下一个目标部队的检查
					if (!pk::is_valid_pos(pos_to_move))
						continue;

					// 保存执行部队附近可移动的坐标
					各目标部队_候选坐标[dst_unit.get_id()] = pos_to_move;
				}

				// 保存通过条件检查的目标部队
				dst_unit_arr.insertLast(dst_unit);
			}

			return dst_unit_arr;
		}

		// 检查策略的目标部队是否满足执行策略的条件
		bool func_对象部队_满足条件(pk::unit @src_unit, pk::unit @dst_unit, int strategy_id, int controller_index)
		{
			// 基本条件：执行部队和目标部队不是敌对关系，则排除
			if (!pk::is_enemy(src_unit, dst_unit))
				return false;

			// 基本条件：目标部队的部队状态不是通常状态，则排除
			if (dst_unit.status != 部队状态_通常)
				return false;

			// 设置条件：如果目标部队的兵力低于标准兵力，则排除
			if (对象部队_兵力条件_适用[controller_index])
			{
				if (int(dst_unit.troops) < 对象部队_兵力标准[controller_index])
					return false;
			}

			// 设置条件：如果目标部队的气力低于标准气力，则排除
			if (对象部队_气力条件_适用[controller_index])
			{
				if (int(dst_unit.energy) < 对象部队_气力标准[controller_index])
					return false;
			}

			// 设置条件：如果目标部队的特定部队能力低于标准能力，则排除
			if (对象部队_能力条件_适用[controller_index])
			{
				if (int(dst_unit.attr.stat[对象部队_适用能力]) < 对象部队_能力标准[controller_index])
					return false;
			}

			// 设置条件：如果目标部队的部队适性低于标准适性，则排除
			if (对象部队_适性条件_适用[controller_index])
			{
				int weapon_id = dst_unit.weapon;
				int dst_tekisei = (weapon_id == 兵器_剑) ? 0 : pk::get_tekisei(dst_unit, weapon_id);
				if (dst_tekisei <= 对象部队_适性标准[controller_index])
					return false;
			}

			// 设置条件：根据不同模式检查执行部队对目标部队策略的成功概率
			int success_chance = get_success_chance(src_unit, dst_unit.pos, strategy_id);
			if (成功概率_适用模式[controller_index] == /*保证成功对象*/ 1)
			{
				// 模式1：如果未满足成功概率，则排除
				/// 注意：模式1仅适用于对成功保证的目标部队施放策略
				if (!pk::rand_bool(success_chance))
					return false;

				/**
					[ 注意 ]

					根据原始文件 '206 计略成功率.cpp' 的内容，如果策略被侦测到，无论如何成功概率都会返回0，
					因此判断策略的成功与否只需判断成功概率是否满足(is_success)即可。
				但为了防止修改 '206 计略成功率.cpp' 文件等情况，添加了检查条件。
				*/
				// 如果目标部队的执行部队的策略被侦测到，则排除
				bool is_detected = strategy_is_detected(src_unit, dst_unit.pos, strategy_id);
				if (is_detected)
					return false;
			}
			else if (成功概率_适用模式[controller_index] == /*保证概率对象*/ 2)
			{
				// 模式2：如果成功概率低于标准概率，则排除
				/// 注意：模式2仅适用于对成功概率保证的目标部队施放策略
				if (success_chance < 执行标准_成功概率[controller_index])
					return false;
			}

			return true;
		}

		// 搜索执行部队移动到目标部队附近的候选坐标（按照远离距离的顺序搜索）
		pk::point get_pos_to_move(pk::unit @src_unit, pk::force @src_force, pk::unit @dst_unit, int strategy_range, int controller_index)
		{
			// 异常状态的部队不应该移动并执行
			if (src_unit.status == 部队状态_混乱 or src_unit.status == 部队状态_伪报 or src_unit.status == 部队状态_挑衅 or src_unit.status == 部队状态_止行)
				return -1;

			if (src_unit.type == 部队类型_运输)
				return -1;

			if (debug_serach_pos_to_move)
			{
				string src_unit_name = pk::decode(pk::get_name(src_unit));
				pk::message_box(pk::encode("开始确认可移动坐标:" + src_unit_name));
			}
			array<pk::point> pos_to_move_arr(0);
			int longest_distance = 0;
			array<pk::point> range_arr = pk::range(dst_unit.pos, 1, strategy_range);
			for (int i = int(range_arr.length) - 1; i >= 0; i--)
			{
				pk::point pos_to_move = range_arr[i];
				if (!pk::is_valid_pos(pos_to_move))
					continue;

				// 基本条件：排除执行部队移动到与其当前坐标相同的候选坐标
				if (pos_to_move == src_unit.pos)
					continue;

				// 基本条件：排除执行部队移动到已存在建筑物或部队的格子上的候选坐标
				pk::hex @hex = pk::get_hex(pos_to_move);
				if (hex.has_building)
					continue;
				if (hex.has_unit)
					continue;

				// 基本条件：排除执行部队移动到无效地形或不可选中的地形的候选坐标
				int terrain_id = hex.terrain;
				if (!pk::is_valid_terrain_id(terrain_id))
					continue;
				if (!pk::is_enabled_terrain(terrain_id))
					continue;

				// 基本条件：排除执行部队移动到不可移动的坐标的候选坐标
				/// 注意：pk::get_movable_pos() 函数已经考虑了 '地形.xml' 和 '169 地形可移动设置.cpp' 中的移动能力设置
				array<pk::point> movable_pos_arr = pk::get_movable_pos(src_unit);
				if (movable_pos_arr.find(pos_to_move) < 0)
					continue;

				if (debug_serach_pos_to_move)
				{
					string terrain_damage_type_name = "无";
					int terrain_damage_type = int(pk::core["terrain"][terrain_id]["damage"]);
					if (terrain_damage_type == 1)
						terrain_damage_type_name = "毒泉";
					else if (terrain_damage_type == 2)
						terrain_damage_type_name = "崖地形";
					range_pos_ = pos_to_move;
					pk::scene(cast<pk::scene_t @>(function() { pk::highlight(main.range_pos_, true); }));
					pk::message_box(pk::encode("损失兵力类型：" + terrain_damage_type_name));
					pk::scene(cast<pk::scene_t @>(function() { pk::remove_all_highlights(); }));
				}

				/**
			[参考] 地形伤害相关

			1. 地形伤害在未研究「智力-诡道行军」的情况下生效
			2. 地形的伤害类型值 - 无(0), 毒泉(1), 崖地形(2)（参考 '地形.xml'）
		*/
				// 设置条件：检查执行部队移动到候选坐标的地形是否属于会造成地形伤害的类型，以决定是否允许移动
				if (候选坐标_搜索_毒泉栈道_除外[controller_index])
				{
					// 排除地形伤害类型的候选坐标
					// 如果执行部队没有名为"技巧_难所行军"的技能，并且地形伤害类型值不等于0（即不是无伤害类型），则执行下一步操作
					int terrain_damage_type = int(pk::core["terrain"][terrain_id]["damage"]);
					if (!pk::has_tech(src_force, 技巧_难所行军) and terrain_damage_type != /*伤害类型值：无*/ 0)
						continue;
				}

				// 设置条件：如果执行部队移动的候选坐标是火灾地形，则排除
				if (候选坐标_搜索_着火地形_除外[controller_index])
				{
					if (pk::is_on_fire(pos_to_move))
						continue;
				}

				// 设置条件：如果执行部队移动的候选坐标位于特定设施的范围内，则排除
				if (候选坐标_搜索_特定设施范围_除外[controller_index])
				{
					if (is_in_facility_range(src_unit, pos_to_move))
						continue;
				}

				// 比较条件：根据执行部队的坐标和执行部队移动的候选坐标之间的距离进行比较（优先选择较远的距离）
				int curr_distance = pk::get_distance(src_unit.pos, pos_to_move);
				if (curr_distance < longest_distance)
					continue;

				pos_to_move_arr.insertLast(pos_to_move);
				longest_distance = curr_distance;
			}

			if (int(pos_to_move_arr.length) == 0)
				return -1;
			return pos_to_move_arr[pk::rand(int(pos_to_move_arr.length))];
		}

		///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		/**

			[参考] 策略执行的基本结构

		1. 处理执行部队的消耗气力
		2. 策略效果
		 1) 执行部队策略施放效果
		 2) 策略成功时的执行部队和目标目标（建筑物、部队）的策略成功效果
		 3) 策略失败时的执行部队和目标目标（建筑物、部队）的策略失败效果
		 4) 执行部队策略施放奖励
			(1) 策略点数
			(2) 能力经验值（智力）
			(3) 功绩
		3. 处理执行部队的行动完成
		4. 处理执行部队的连环特技
		5. 处理目标部队的对策特技
		*/
		void
			func_执行计略(pk::unit @src_unit, pk::force @src_force, pk::unit @dst_unit, int strategy_id, int energy_cost, int controller_index, bool is_deployed)
		{
			// 消耗气力
			pk::add_energy(src_unit, -energy_cost, false);

			// 执行计略（普通释放）
			bool is_success = func_计略效果(src_unit, src_force, dst_unit, strategy_id, /*is_chain_reaction*/ false, /*is_counter_plan*/ false, controller_index, is_deployed);

			/**
				[ 参考 ] 连环技能相关

				1. 连环技能需要在计略首次执行成功后，才会触发相邻单位
				2. 可触发连环技能的计略 - 火计、灭火、威慑、干扰、镇定（伏兵、掩体、咒术、雷电不适用）
				3. 火计计略首次施放时，会触发相邻单位的连环技能（若相邻单位有多个，随机选择）
				 1) 部队施放成功，触发相邻部队
				 2) 建筑施放成功，相邻建筑不会触发（城市除外）
				 3) 部队施放成功，相邻建筑不会触发
				 4) 建筑施放成功，触发相邻部队
				4. 火计连环触发时，不会输出连环技能的触发台词
			*/

			// 若普通施放成功且执行单位具有连环技能，则执行附加计略（连环触发）

			if (is_success and src_unit.has_skill(特技_连环))
			{
				// 目标部队的邻近部队搜索
				pk::unit @dst_neighbor_unit = get_dst_neighbor_unit(src_unit, dst_unit);
				if (pk::is_alive(dst_neighbor_unit))
				{
					func_计略效果(src_unit, src_force, dst_neighbor_unit, strategy_id, /*is_chain_reaction*/ true, /*is_counter_plan*/ false, controller_index, is_deployed);
				}
			}

			// 普通施展计谋失败且目标部队拥有反计技能的情况下，执行额外计谋（反计发动）
			/**
				[ 参考 ] 反计技能相关

				1. 当执行部队的连环技能发动时，目标部队的反计技能不会发动（无法反击连环）
				2. 当目标部队的反计技能发动时，执行部队的反计技能不会发动（无法反击反计）
				3. 反计技能发动时，将对执行计谋的部队转变为目标部队（需注意使用变量）
				4. 反计技能发动时，所施展的计谋与之前从执行部队尝试施展的计谋相同，但计谋施展效果与基础效果不同
				 - 计谋执行部队的计谋施展效果中的对话、音效、特效会有所不同（音效相同）
			*/
			if (!is_success and dst_unit.has_skill(特技_反计))
			{
				// 目标部队对执行部队尝试施展的计谋进行反向施展
				func_计略效果(dst_unit, src_force, src_unit, strategy_id, /*is_chain_reaction*/ false, /*is_counter_plan*/ true, controller_index, is_deployed);
			}

			// 执行部队行动完成
			src_unit.action_done = true;
		}

		/**
			[ 参考 ] 计谋效果（函数）

			1. 突入: pk::face_cutin(int id) / pk::face_cutin(unit@ unit)
			 - 当触发暴击时显示
			 - 只对玩家势力的部队显示
			 - 仅在 '18 other.xml' 的 '계략컷인' 设置为 'true' 时显示
			2. 对话: pk::msg_param 结构体属性的使用
			 - 可调用 msg 文件夹的 s11 文件中的对话（与计谋相关 - S11MSG01.s11 文件）
			3. 音效: pk::play_voice(person@ person)
			4. 音效: pk::play_se(int id, pk::point pos) / pk::play_se(int id)
			5. 特效: pk::create_effect(int id, pk::point pos)
			6. 处理: 使用结构体属性或函数
			 - 根据每个计谋需要，可能包含对话、音效、特效等
			7. 等待: pk::wait(int min, int max)
			 - 用于确保特效动画的顺利进行
			 - 如果不在 pk::is_in_screen() 函数内使用，可能导致程序强制退出
			 - 如果不在 pk::scene() 函数内使用，可能导致缓冲区溢出：pk::scene(cast<pk::scene_t@>(function(){pk::wait(1, 1000);}));
		*/
		/**
			[ 参考 ] 各计谋相关函数

			1. 火系，水系，雷系: pk::create_fire(pk::point pos, int timer(回合数), unit@ by = null, bool critical = false)
			 - 包括效果：特效（火焰生成和消失），音效（火焰声音）
			2. 伪报，扰乱，镇静: pk::set_status(unit@ self, unit@ by, int status, int time, bool sound = true)
			 - 参数：self（受影响部队），by（状态施加者），status（部队状态），time（状态计数器），sound（是否播放音效）
			 - 包括效果：日志信息（目标部队状态变化），对话（目标部队状态变化），音效（目标部队状态变化），特效（目标部队状态变化）
			3. 埋伏，土系: pk::attack(unit@ unit, hex_object@ target)

		*/
		bool func_计略效果(pk::unit @src_unit, pk::force @src_force, pk::unit @dst_unit, int strategy_id, bool is_chain_reaction, bool is_counter_plan, int controller_index, bool is_deployed)
		{
			// 执行部队和目标部队的计略相关武装确认（剪入、对话、音声相关）
			/// 参考：连环和反计策技能触发时基本上持有该技能的武装将成为与计略效果相关的主体（剪入有例外）
			pk::person @src_person = pk::get_person(src_unit.leader);
			pk::person @dst_leader = pk::get_person(dst_unit.leader);
			if (is_chain_reaction)
				@src_person = pk::get_person(src_unit.who_has_skill(特技_连环));
			else if (is_counter_plan)
				@src_person = pk::get_person(src_unit.who_has_skill(特技_反计));

			// 计略暴击判断
			bool is_critical = pk::rand_bool(get_critical_chance(src_unit, dst_unit.pos, strategy_id));

			// 执行部队的计略发动效果：剪入、对话、音声、音效、效果
			func_计略发动效果_执行部队(src_unit, src_person, dst_leader, strategy_id, is_critical, is_chain_reaction, is_counter_plan);

			// 根据模式应用计略成功率和侦查判断
			bool is_success = pk::rand_bool(get_success_chance(src_unit, dst_unit.pos, strategy_id));
			bool is_detected = strategy_is_detected(src_unit, dst_unit.pos, strategy_id);
			if (!is_chain_reaction and !is_counter_plan and 成功概率_适用模式[controller_index] == /*保证成功对象*/ 1)
			{
				/// 参考：对于“模式1”，在搜索目标部队时只保存符合成功率的情况，所以这里默认为必定成功
				///        （但即便是“模式1”，由于连环和反计策技能导致计略发动时目标有所变化时，需要重新确认目标的成功率）
				is_success = true;
				is_detected = false;
			}

			/// 参考：如果计略被侦查，则一定无法成功，所以只需判断计略的成功与否（是否成功）即可
			if (is_success)
			{
				// 目标部队的计略成功效果：对话、音声、音效、效果、处理
				func_计略成功效果_目标部队(src_unit, dst_unit, dst_leader, strategy_id, is_critical);
			}
			else
			{
				// 目标部队的计略失败效果：对话、音声、音效、效果
				func_func_计略失败效果_目标部队(dst_unit, dst_leader, is_detected);
			}

			// 执行部队的计略发动奖励：计策点、能力经验、功绩
			/// 参考：计策点、经验、功绩等基本上只有计略发动的执行部队可以获得（即使由于连环或反计策导致计略发动时也是一样）
			func_计略发动奖励_执行部队(src_unit, src_force, dst_unit, is_success, is_critical, strategy_id);

			if (debug_strategy_success_info)
			{
				string src_force_name = pk::decode(pk::get_name(src_force));
				string src_unit_name = pk::decode(pk::get_name(src_unit));
				pk::building @building = pk::get_building(pk::get_service(src_unit));
				string src_building_name = pk::is_alive(building) ? pk::decode(pk::get_name(building)) : "诠冼";
				string dst_unit_name = pk::decode(pk::get_name(dst_unit));
				string src_person_name = pk::decode(pk::get_name(src_person));
				string strategy_info = (strategy_id == 计略_扰乱) ? "扰乱" : "伪报";
				string success_info = (is_success) ? "成功" : "失败";
				string skill_info = (is_chain_reaction) ? "发动连环" : (is_counter_plan ? "反计发动" : "反击未发动");
				// pk::info(skill_info + " : " + src_force_name + "的 " + src_person_name + "(" + (is_deployed ? "出征部队(" + src_building_name + ")" : "野战部队") + ")");
				// pk::info(src_unit_name + "对 " + dst_unit_name + "发动 " + strategy_info + " " + success_info + " (" + skill_info + ")");
			}

			return is_success;
		}
		void func_计略发动效果_执行部队(pk::unit @src_unit, pk::person @src_person, pk::person @dst_leader, int strategy_id, bool is_critical, bool is_chain_reaction, bool is_counter_plan)
		{
			if (pk::is_in_screen(src_unit.pos))
			{
				// 当执行部队连续发动时的额外台词
				if (is_chain_reaction)
				{
					// 执行部队连环触发对话（持有连环特技装备）
					say_message(7574, /*p0*/ src_person, /*p1*/ null, /*u0*/ null, /*p0_u*/ src_unit);

					// 等待
					pk::scene(cast<pk::scene_t @>(function() { pk::wait(1, 500); }));
				}

				// 执行部队计略施展开场动画
				/**
					[ 参考 ] 开场动画相关

					1. 只有玩家势力（包括代命军团）的部队触发暴击时才播放
					2. 开场动画的人物
					  1) 普通施展：部队的主将
					  2) 连环触发：部队内有连环特技的装备
					  3）反击触发：部队的主将
				*/
				if (bool(pk::core["strategy_cutin"]) and is_critical and src_unit.is_player())
				{
					// 连环触发时
					if (is_chain_reaction)
					{
						// 开场动画语音
						pk::play_voice(33, src_person);

						// 开场动画音效
						pk::play_se(25);

						// 开场动画效果
						int cutin_id = pk::get_cutin_id(src_person);
						pk::face_cutin(cutin_id);
					}

					// 普通施展和反击触发时
					else
					{
						// 开场动画效果
						pk::face_cutin(src_unit); // 包括语音和音效
					}
				}

				// 执行部队计略施展对话
				int msg_id = (is_counter_plan) ? 7575 : (strategy_id == 计略_扰乱 ? 7108 : 7095);
				pk::person @person1 = (is_counter_plan) ? null : dst_leader;
				say_message(msg_id, /*p0*/ src_person, /*p1*/ person1, /*u0*/ null, /*p0_u*/ src_unit);

				// 执行部队计略施展语音
				pk::play_voice(50, src_person);

				// 执行部队计略施展音效
				if (is_counter_plan)
					pk::play_se(91, src_unit.pos);
				else if (is_critical)
					pk::play_se(79);
				else
					pk::play_se(57, src_unit.pos);

				// 执行部队计略施展效果
				int effect_id = (is_counter_plan) ? 77 : (is_critical ? 79 : 58);
				pk::create_effect(effect_id, src_unit.pos);

				// 等待
				pk::scene(cast<pk::scene_t @>(function() { pk::wait(1, 1000); }));
			}
		}

		void func_计略成功效果_目标部队(pk::unit @src_unit, pk::unit @dst_unit, pk::person @dst_leader, int strategy_id, bool is_critical)
		{
			if (pk::is_in_screen(dst_unit.pos))
			{
				// 目标部队计谋成功台词
				int msg_id = (strategy_id == 计略_扰乱) ? 5846 : 5860;
				pk::unit @unit0 = (strategy_id == 计略_扰乱) ? null : dst_unit;
				say_message(msg_id, /*p0*/ dst_leader, /*p1*/ null, /*u0*/ unit0, /*p0_u*/ dst_unit); // Included in pk::set_status() function

				// 目标部队计谋成功音效
				int voice_id = pk::rand_bool(50) ? 66 : 68;
				pk::play_voice(voice_id, dst_leader);

				// 目标部队计谋成功音效1
				int sound1_id = dst_unit.is_player() ? 3 : 2;
				pk::play_se(sound1_id); // Included in pk::set_status() function

				// 目标部队计谋成功音效2
				int sound2_id = (strategy_id == 计略_扰乱) ? 39 : 40;
				pk::play_se(sound2_id, dst_unit.pos); // Included in pk::set_status() function
			}

			// 目标部队计谋成功效果、处理
			/// 注意: 如果未触发暴击，则混乱和伪报状态计数器根据概率设置为2或1（概率未知）
			int status = (strategy_id == 计略_扰乱) ? 部队状态_混乱 : 部队状态_伪报;
			int time = (is_critical) ? 5 : (pk::rand_bool(20) ? 2 : 1);
			bool sound = false;
			pk::set_status(dst_unit, src_unit, status, time, sound); // Includes log message, dialogues (for the target unit), sound effects (for the target unit), and effects

			if (pk::is_in_screen(dst_unit.pos))
			{
				// 等待 待机
				pk::scene(cast<pk::scene_t @>(function() { pk::wait(1, 500); }));
			}
		}

		void func_func_计略失败效果_目标部队(pk::unit @dst_unit, pk::person @dst_leader, bool is_detected)
		{
			if (pk::is_in_screen(dst_unit.pos))
			{
				// 目标部队计略失败对话
				say_message(7206, /*p0*/ dst_leader, /*p1*/ null, /*u0*/ null, /*p0_u*/ dst_unit);

				/**
					[ 参考 ] 关于计略被侦查的说明

					1. 当计略被侦查时，计略防御效果会触发，因此与计略失败的情况不同
					2. 特定技能可对计略进行侦查（以206计略成功概率.cpp为准）
					   - 神算及侦查技能需要满足执行部队的目标对象（部队）的情报优势条件才能触发侦查
					1) 神算: 火计, 伪报, 扰乱, 伏兵, 内讧
					2) 侦察: 火计, 伪报, 扰乱, 伏兵, 内讧
					3) 洞察: 火计, 伪报, 扰乱, 伏兵, 内讧, 妖术
					4) 火神: 火计
					5) 名镜: 伪报, 扰乱
					6) 规律: 伪报
					7) 沉着: 扰乱
				*/
				if (is_detected)
				{
					// 目标部队计略失败（侦查）音效
					pk::play_voice(69, dst_leader);

					// 目标部队计略失败（侦查）音效
					pk::play_se(95, dst_unit.pos);

					// 目标部队计略失败（侦查）效果
					pk::create_effect(84, dst_unit.pos);
				}
				else
				{
					// 目标部队计略失败（简单失败）音效
					pk::play_voice(70, dst_leader);

					// 目标部队计略失败（简单失败）音效，效果：无
				}

				// 等待
				pk::scene(cast<pk::scene_t @>(function() { pk::wait(1, 500); }));
			}
		}

		void func_计略发动奖励_执行部队(pk::unit @src_unit, pk::force @src_force, pk::unit @dst_unit, bool is_success, bool is_critical, int strategy_id)
		{
			// 获得计略点数
			int tech_point = (is_success) ? 10 : 0;
			ch::add_tp(src_force, tech_point, dst_unit.pos); // 包括效果和音效

			// 提升能力经验值：智力
			int stat_exp = (is_success) ? 3 : 1;
			pk::add_stat_exp(src_unit, 武将能力_智力, stat_exp);

			// 提升功绩值
			int kouseki_point = (is_success) ? (is_critical ? 200 : 100) : 20;
			pk::add_kouseki(src_unit, kouseki_point);
		}

		/// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

		// 返回是否为普通游戏：非决战败北、教程、任务进行中
		bool is_normal_game()
		{
			return (!pk::is_campaign() && !pk::is_mission_running());
		}

		// 返回部队的操作主体索引
		int get_controller_index(pk::unit @unit)
		{
			return (unit.is_player() ? /*玩家委任军团*/ 0 : /*电脑*/ 1);
		}

		int func_部队附近_敌部队数(pk::unit @unit, int distance)
		{
			int enemy_units = 0;
			array<pk::point> range = pk::range(unit.pos, 1, distance);
			for (int i = 0; i < int(range.length); i++)
			{
				pk::unit @enemy_unit = pk::get_unit(range[i]);
				if (!pk::is_alive(enemy_unit))
					continue;
				if (!pk::is_enemy(unit, enemy_unit))
					continue;

				enemy_units++;
			}

			return enemy_units;
		}

		// 计谋执行部队和目标部队的台词输出:调用msg文件的台词(计谋相关内容- S11MSG01.s11文件)
		void say_message(int msg_id, pk::person @p0, pk::person @p1, pk::unit @u0, pk::unit @p0_u)
		{
			pk::msg_param msg_param(msg_id, p0, p1);
			@msg_param.unit[0] = @u0;
			pk::say(pk::get_msg(msg_param), p0, p0_u);
		}

		// 返回策略执行部队的消耗气力
		int get_energy_cost(pk::unit @src_unit, int strategy_id)
		{
			return cast<pk::func205_t>(pk::get_func(205))(src_unit, strategy_id);
		}

		// 返回策略执行部队对目标部队的成功概率
		int get_success_chance(pk::unit @src_unit, pk::point dst_pos, int strategy_id)
		{
			return cast<pk::func206_t>(pk::get_func(206))(src_unit, src_unit.pos, dst_pos, strategy_id).first;
		}

		// 返回策略目标部队对执行部队的侦测结果
		bool strategy_is_detected(pk::unit @src_unit, pk::point dst_pos, int strategy_id)
		{
			return cast<pk::func206_t>(pk::get_func(206))(src_unit, src_unit.pos, dst_pos, strategy_id).second;
		}

		// 返回策略执行部队的暴击概率
		int get_critical_chance(pk::unit @src_unit, pk::point dst_pos, int strategy_id)
		{
			return cast<pk::func207_t>(pk::get_func(207))(src_unit, src_unit.pos, dst_pos, strategy_id);
		}

		// 返回目标单位相邻坐标中存在的执行单位的敌对单位
		pk::unit @get_dst_neighbor_unit(pk::unit @src_unit, pk::unit @dst_unit)
		{
			array<pk::unit @> dst_neighbor_unit_arr(0);
			array<pk::point> ring_arr = pk::ring(dst_unit.pos, 1);
			for (int i = 0; i < int(ring_arr.length); i++)
			{
				pk::point dst_neighbor_pos = ring_arr[i];
				pk::unit @dst_neighbor_unit = pk::get_unit(dst_neighbor_pos);
				if (!pk::is_alive(dst_neighbor_unit))
					continue;
				if (!pk::is_enemy(src_unit, dst_neighbor_unit))
					continue;
				if (dst_neighbor_unit.status != 部队状态_通常)
					continue;

				dst_neighbor_unit_arr.insertLast(dst_neighbor_unit);
			}

			if (int(dst_neighbor_unit_arr.length) == 0)
				return null;
			return dst_neighbor_unit_arr[pk::rand(int(dst_neighbor_unit_arr.length))];
		}

		// 判断执行单位是否在特定坐标的设施范围内
		bool is_in_facility_range(pk::unit @src_unit, pk::point pos)
		{
			array<int> 范围性陷阱 = { 设施_火种, 设施_火焰种, 设施_业火种, 设施_火船 };
			array<int> 直线型陷阱 = { 设施_火球, 设施_火焰球, 设施_业火球, 设施_落石 };

			///  设施的最大范围为0到10（参见 '设施.xml'）
			array<pk::point> range_arr = pk::range(pos, 1, 10);
			for (int pos_index = 0; pos_index < int(range_arr.length); pos_index++)
			{
				pk::point range_pos = range_arr[pos_index];
				pk::building @building = pk::get_building(range_pos);
				if (!pk::is_alive(building))
					continue;

				// 如果不是指定的可回避设施，则排除
				///  可回避设施数组
				int facility_id = building.facility;
				pk::facility @facility = pk::get_facility(facility_id);
				if (回避对象_设施[facility.type].find(facility_id) < 0)
					continue;

				// 非陷阱类设施的势力为友方时排除
				if (facility.type != 设施类型_陷阱 and !pk::is_enemy(src_unit, building))
					continue;

				///  比较设施的最大距离和坐标距离时，在城市的情况下应该与 '最大距离+1' 进行比较（因为城市占据地图上两个格子的范围）
				int min_range = facility.min_range;
				int max_range = (facility_id == 设施_都市) ? facility.max_range + 1 : facility.max_range;
				int distance = pk::get_distance(pos, range_pos);
				bool auto_attack = bool(pk::core["facility"][facility_id]["auto_attack"]);

				// 检查部队是否存在于设施范围内
				if (distance >= min_range and distance <= max_range)
				{
					// 检查部队是否位于设施范围内：石兵八阵、范围型陷阱
					if (facility_id == 设施_石兵八阵 or 范围性陷阱.find(facility_id) >= 0)
						return true;

					// 检查部队是否位于设施范围内且与该设施处于直线上：直线型陷阱（
					else if (直线型陷阱.find(facility_id) >= 0)
					{
						// 只检查5格范围内的情况
						int direction = pk::get_direction(pos, range_pos);
						if (distance <= 5 and 方向对应的直线坐标索引[direction].find(pos_index) >= 0)
							return true;
					}

					// 检查部队是否在设施范围内，并且检查该设施是否启用了自动攻击"
					/// 可回避的设施数组
					else if (auto_attack)
						return true;
				}
			}

			return false;
		}
		// 返回目标部队周围存在的执行部队的敌军部队数量和士兵数量，友军部队数量和士兵数量的数组
		array<int> func_对象部队_附近部队_相关信息_数组(pk::unit @src_unit, pk::unit @dst_unit, int distance)
		{
			array<int> units_and_troops_info(4, 0);
			array<pk::point> range = pk::range(dst_unit.pos, 1, distance);
			for (int i = 0; i < int(range.length); i++)
			{
				pk::unit @unit = pk::get_unit(range[i]);
				if (!pk::is_alive(unit))
					continue;
				if (@unit == @src_unit)
					continue;

				if (pk::is_enemy(src_unit, unit))
				{
					// 数组索引 0: 目标部队周围的执行部队的敌军部队数量
					units_and_troops_info[0]++;

					// 数组索引 1: 目标部队周围的执行部队的敌军士兵数量
					units_and_troops_info[1] += unit.troops;
				}
				else
				{
					// 数组索引 2: 目标部队周围的执行部队的友军部队数量
					units_and_troops_info[2]++;

					// 数组索引 3: 目标部队周围的执行部队的友军士兵数量
					units_and_troops_info[3] += unit.troops;
				}
			}

			return units_and_troops_info;
		}

		/**
			[ 参考 ] 城市攻防条件

			1. 针对满足城市防御条件的目标部队优先执行计谋
			2. 城市防御判断条件
				1) 势力条件：目标部队所在区域城市为执行部队势力的友军城市
				2) 距离条件：目标部队所在区域城市与目标部队之间的距离小于一定距离
				3) 兵种条件：目标部队的兵种为攻城兵种
				4) 耐久条件：目标部队所在区域城市的耐久度不超过城市最大耐久度的一定比例
		*/
		bool func_攻城战_防御条件_满足与否(pk::unit @src_unit, pk::unit @dst_unit)
		{
			pk::city @area_city = pk::get_city(pk::get_city_id(dst_unit.pos));
			if (!pk::is_alive(area_city))
				return false;

			// 势力条件：目标部队所在区域城市为执行部队势力的敌军城市时排除
			if (pk::is_enemy(area_city, src_unit))
				return false;

			// 距离条件：目标部队所在区域城市与目标部队之间的距离大于等于一定距离时排除
			/// 注意：由于城市在地图上占据两个格子的范围，所以实际比较时需要减去1
			int distance = pk::get_distance(area_city.get_pos(), dst_unit.pos) - 1;
			if (distance >= 攻城战_防御条件_标准距离)
				return false;

			// 兵种条件：目标部队的兵种不是攻城兵种时排除
			/// 注意：考虑到可能经过水域攻击的情况，这里只考虑当前地形的兵种，而不是海上兵种
			int dst_ground_wpn_id = pk::get_ground_weapon_id(dst_unit);
			int dst_heishu = pk::equipment_id_to_heishu(dst_ground_wpn_id);
			if (dst_heishu != 兵种_兵器)
				return false;

			// 耐久条件：目标部队所在区域城市的耐久度超过城市最大耐久度的一定比例时排除
			if (int(pk::get_hp(area_city)) > int(area_city.max_hp) * 攻城战_防御条件_标准耐久比率 / 100)
				return false;

			// 兵力条件：目标部队所在区域城市的兵力超过一定标准值时排除
			if (int(area_city.troops) > 攻城战_防御条件_兵力标准)
				return false;

			return true;
		}

		///	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	}

	Main main;
}